<?php
	/**
	  * @package	MyDebuger
	  * @name		MyException
	  * @brief		Clase para realizar excepciones personalizadas
	  * @author		Hermann D. Schimpf <hschimpf@gschimpf.com>
	  * @license	http://opensource.org/licenses/gpl-2.0.php
	  * @date		2009-12-29
	  * @version	0.5.7
  	**/

	final class MyException extends Exception implements MyVersions {
		/* version de la clase */
		private static $version			= 0;
		/* subversion de la clase */
		private static $subversion		= 5;
		/* numero de revision de la clase */
		private static $revision		= 7;

		/* datos de la fuente */
		private $fuente	= False;
		/* datos del destino */
		private $destino	= False;
		/* color para los mensajes */
		private $color		= '#c00';
		/* ruta de ejecucion */
		private $ruta		= Array();

		public static final function getVersion() {
			/* retornamos la version actual de la clase */
			return 'v' . self::$version . '.' . self::$subversion . '.' . self::$revision;
		}

		public function __construct($e) {
			/* verificamos si el parametro es un string */
			if (gettype($e) === 'string') {
				/* creamos el padre */
				parent::__construct($e);
				/* almacenamos la ruta */
				$this->ruta = $this->getTrace();
			} else {
				/* almacenamos la ruta */
				$this->ruta = $e->getTrace();
				/* creamos el padre */
				parent::__construct($e->getMessage());
			}
		}

		private function getFormat($text, $style) {
			/* retornamos la cadena con formato */
			return "|font style='$style;'|$text|/font|";
		}

		/* creamos una nueva funcion para obtener los mensajes */
		public final function getMensaje() {
			/* obtenemos los datos de la excepcion */
			$this->getData();
			/* retornamos el mensaje */
			return $this->getFormat($this->armarMensaje(), 'color:' . $this->color);
		}

		private function getData() {
			/* almacenamos los datos de la fuente */
			$this->fuente = $this->ruta[(count($this->ruta) - 1)];
			/* almacenamos los datos del destino */
			$this->destino = $this->ruta[0];
		}

		private function armarMensaje() {
			/* agregamos al mensaje la ubicacion de ejecucion (executed in..) */
			$this->agregarDestino();
			/* agregamos al mensaje la ubicacion de la llamada (called from..) */
			$this->agregarFuente();
			/* combinamos el destino y la fuente */
			$this->combinarMensaje();
			/* retornamos el mensaje */
			return $this->message;
		}

		private function agregarDestino() {
			/* almacenamos la ubicacion de ejecucion */
			$this->destino = $this->getExecutedIn($this->destino);
		}

		private function getExecutedIn($data) {
			/* retornamos la cadena */
			return ', executed in ' . $this->getFileLine($data);
		}

		private function getFileLine($data) {
			/* retornamos la cadena con el fichero y la linea */
			return $this->getFormat((
				/* verificamos si no tenemos el fichero */
				!isset($data['file']) ?
				/* retornamos unknown */
				'unknwon' :
				/* reemplazamos algunos caracteres */
				preg_replace(
					/* buscamos la posible aparicion de la cadena 'eval()'d code' */
					'/(\([0-9]+\) : eval\(\)\'d code)+/i',
					/* los eliminamos */
					'',
					/* del nombre del fichero */
					basename($data['file'])
				)
			/* finalizamos los parametros de getFormat y agregamos la linea del fichero */
			), 'font-style:italic') . (
				/* verificamos si tenemos la linea */
				!isset($data['line']) ?
				/* retornamos false */
				False :
				/* retornamos la linea */
				':' . $data['line']
			);
		}

		private function agregarFuente() {
			/* obtenemos la funcion que se llamo */
			$function = $this->getFunction($this->fuente);
			/* obtenemos el fichero de ejecucion */
			$fileLine = $this->getFileLine($this->fuente);
			/* almacenamos la cadena completa */
			$this->fuente = " [$function called from $fileLine]";
		}

		private function getFunction($data) {
			/* retornamos la cadena con el nombre de la funcion llamada */
			return $this->getFormat((
				/* si no es una clase */
				$data['class'] == '' ?
				/* agregamos la palabra 'Function' */
				'Function ' :
				/* si es una clase agregamos el nombre de la misma */
				$data['class'] . '::'
			/* agregamos el metodo o funcion que se llamo */
			) . $data['function'] . '()', 'font-style:italic');
		}

		private function combinarMensaje() {
			/* verificamos si la cadena no esta en el mensaje */
			if (!stristr($this->message, ', executed in'))
				/* agregamos al mensaje el destino */
				$this->message .= $this->destino;
			/* agregamos al mensaje la fuente */
			$this->message .= $this->fuente;
		}

		private function armarFuente() {
			/* obtenemos el nombre de la funcion llamada */
			$functionCalled = (
				/* si no es una clase */
				$this->fuente['class'] == '' ?
				/* agregamos la palabra 'Function' */
				'Function ' :
				/* sino, si es una clase agregamos el nombre de la misma */
				$this->fuente['class'] . '::'
			/* agregamos el metodo o funcion que se llamo */
			) . $this->fuente['function'] . '()';
			/* armamos la cadena con el nombre del fichero, linea de error y la funcion */
			$cadenaFile = $this->getFormat($functionCalled, 'font-style:italic') .(
				/* verificamos si existe un fichero fuente */
				isset($this->fuente['file']) ?
				/* si existe agregamos el fichero fuente */
				' called from ' . $this->getFormat(basename($this->fuente['file']), 'font-style:italic') . ':' . $this->fuente['line'] :
				/* si no existe puede que se alla llamado desde el metodo __destruct de la clase */
				''
			);
			/* almacenamos la cadena de datos del fichero */
			$this->fuente = " [$cadenaFile]";
		}
	}
?>